﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Markup;
using System.Windows.Threading;

namespace Gestalt
{
    public class XamlParse
    {
        private IDictionary<string, string> parameters;
        string htmlId;
        private Dictionary<string, object> namedElements = new Dictionary<string, object>();
        private FrameworkElement firstChild;
        private UIElement rootVisual;
        public delegate void DelType();
        DelType afterParse;

        public XamlParse(string htmlId)
        {
            this.htmlId = htmlId;
        }

        public UIElement ParseXamlInPlace(DelType afterParse)
        {
            this.afterParse = afterParse;

            int width = 0;
            string w = DomAttribute(htmlId, "width");
            if (w != "") width = Convert.ToInt32(w);

            int height = 0;
            string h = DomAttribute(htmlId, "height");
            if (h != "") height = Convert.ToInt32(h);

            Canvas canvas = new Canvas();

            canvas.Width = width;
            canvas.Height = height;
            canvas.Name = "LayoutRoot";

            rootVisual = canvas;
            namedElements.Add("LayoutRoot", canvas);

            if (htmlId == "GestaltDOMOnly")
            {
                firstChild = (FrameworkElement)rootVisual;
                Deployment.Current.Dispatcher.BeginInvoke(afterParse);
            }
            else
            {
                string src = DomAttribute(htmlId, "src");

                if (src == null || src == "")
                {

                    string xaml = InnerXaml(htmlId);
                    try
                    {
                        UIElement visual = (UIElement)XamlReader.Load(xaml);
                        ((Canvas)rootVisual).Children.Add(visual);
                        firstChild = (FrameworkElement)((Canvas)rootVisual).Children.First();
                    }
                    catch (XamlParseException e)
                    {
                        string errorMsg = "Syntax error parsing your embedded XAML.  <a href='http://visitmix.com/labs/gestalt/faqs.html'>See the FAQ</a> for workarounds to known issues.  The error message was:\r\n";
                        int inner = e.Message.IndexOf("--- Inner Exception");
                        if (inner > 1)
                        {
                            errorMsg += e.Message.Substring(0, inner);
                        }
                        else
                        {
                            errorMsg += e.Message;
                        }

                        GestaltApp.reportError(errorMsg);
                        return null;
                    }


                    Deployment.Current.Dispatcher.BeginInvoke(afterParse);
                }
                else
                {
                    Uri srcUri = new Uri(HtmlPage.Document.DocumentUri, src);

                    WebClient xamlDownload = new WebClient();
                    xamlDownload.DownloadStringCompleted += new DownloadStringCompletedEventHandler(xamlDownload_DownloadStringCompleted);
                    xamlDownload.DownloadStringAsync(srcUri);
                }
            }

            return rootVisual;
        }

        void xamlDownload_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            string xaml = AddNamespaces(e.Result);
            UIElement visual = (UIElement)XamlReader.Load(xaml);
            ((Canvas)rootVisual).Children.Add(visual);
            firstChild = (FrameworkElement)((Canvas)rootVisual).Children.First();

            Deployment.Current.Dispatcher.BeginInvoke(afterParse);
        }

        string InnerHTML(string id)
        {
            return DomAttribute(id, "innerHTML");
        }

        string InnerXaml(string id)
        {
            string content = InnerHTML(id).Trim();
            if (content == "") return "";
            content = AddNamespaces(content);

            if (HtmlPage.BrowserInformation.Name != "Microsoft Internet Explorer")
            {
                /*
                 * The other browser convert the XML to lowercase (unbelievable)
                 * Need to fix it up
                 */
                Filters x = new Filters();
                content = x.Filter(content);
            }

            return content;

        }

        string AddNamespaces(string content)
        {
            int space = content.IndexOf(" ");
            int bracket = content.IndexOf(">");
            if (bracket < space) space = bracket;

            string left = content.Substring(0, space) + " ";
            string right = " " + content.Substring(space, content.Length - space);

            string decl = "xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"";
            if (!right.Contains(decl)) right = decl + right;

            decl = "xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"";
            if (!right.Contains(decl)) right = decl + " " + right;

            decl = "xmlns:xaml=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"";
            if (!right.Contains(decl)) right = decl + " " + right;

            return left + right;
        }

        string DomAttribute(string id, string attributeName)
        {
            string content = "";
            try
            {
                HtmlElement node = HtmlPage.Document.GetElementById(id);
                if (node != null)
                {
                    if (attributeName == "innerHTML")
                        content = (string)node.GetProperty("innerHTML");
                    else
                        content = node.GetAttribute(attributeName);
                }
            }
            catch (Exception e) { }
            return content;
        }

        public object this[string name]
        {
            get
            {
                if (namedElements.ContainsKey(name)) return namedElements[name];
                else
                {
                    var node = firstChild.FindName(name);
                    if (node != null)
                    {
                        namedElements.Add(name, node);
                        return node;
                    }
                    else return null;
                }
            }
        }


    }
}
